#include <std.h>
#include <pio.h>
#include <type.h>
#include <dint.h>
#include <biosdisk.h>
#include <memory.h>

#define SECTOR 512
#define BOOT_SIG 0xaa55
#define END_ATTR_MARK 0xffffffff

struct ntfs_boot	{
	u8 jmp[3];
	u8 sysid[8];
	u16 sectsize;
	u8 sectperclust;
	u8 undef0[7];
	u8 mediadesc;
	u8 undef1[2];
	u16 sectpertrack;
	u16 heads;
	u8 undef2[8];
	u16 res0;
	u16 res1;
	u64 nsect;	/*Number of sectors in the storage unit*/
	u64 mftdatalcn;	/*LCN (Logical cluster number) of mft data attribute at VCN (Virtual cluster number) 0*/
	u64 mftmirrdatalcn; /*For mftmirr*/
	u32 filerecsz;	/*File record size in clusters*/
	u32 indexrecsz; /*Index record size in clusters*/
	u64 volserial;
	u8 undef3[13];
	u8 bootloader[0x1a1];
	u16 sign;
}__attribute__((packed));

struct mft_file_record	{
	u8 magic[4];
	u16 usoffset;	/*Update sequence offset*/
	u16 ussz_words;	/*Update sequence size in words*/
	u64 lsn; /*Logfile sequence number*/
	u16 seqn; /*Sequence number*/
	u16 hardlinkcount;
	u16 attroffset; /*offset to first attribute*/
	u16 flags;
	u32 realfilerecsz; /*Real size*/
	u32 allocfilerecsz;	/*Allocated size*/
	u64 fileref; /*File reference to the base file record*/
	u16 nextattr;
	u16 align;
	u32 mftrecnum; /*This record*/
	u16 usn;
}__attribute__((packed));

#define FREC_IN_USE 0x1
#define FREC_DIR 0x2


/*Resident attribute*/
struct attr_resident	{
	u32 type;
	u32 len;
	u8 nres_flag;	/*This is 0 for resident*/
	u8 name_len;	/*This is zero for unnamed attribute*/
	u16 name_offset;
	u16 flags;
	u16 attr_id;
	u32 attr_len;
	u16 attr_offset;
	u8 indexed_flag;
	u8 padding;
	/*Here the name and/or the attribute is present*/
}__attribute__((packed));

/*Non-resident attribute*/
struct attr_nonresident	{
	u32 type;
	u32 len;
	u8 nres_flag;	/*This is 1 for non-resident*/
	u8 name_len;	/*This is zero for unnamed attribute*/
	u16 name_offset;
	u16 flags;
	u16 attr_id;
	u64 start_vcn;
	u64 last_vcn;
	u16 datarun_offset; /*Offset to the dataruns*/
	u16 compunitsz;	/*compression unit size*/
	u32 padding;
	u64 alloc_sz;
	u64 real_sz;
	u64 stream_datasz;	/*Initialized data size of the stream*/
	/*Here the name and/or the dataruns are present*/
}__attribute__((packed));

#define ATTR_STD_INFO	0x10
#define ATTR_ATTR_LIST	0x20
#define ATTR_FILE_NAME	0x30
#define ATTR_VOL_VER_NT	0x40
#define ATTR_OBJ_ID_2K	0x40
#define ATTR_SEC_DESC	0x50
#define ATTR_VOL_NAME	0x60
#define ATTR_VOL_INFO	0x70
#define ATTR_DATA		0x80
#define ATTR_INDX_ROOT	0x90
#define ATTR_INDX_ALLOC	0xa0
#define ATTR_BITMAP		0xb0
#define ATTR_SYMLINK_NT	0xc0
#define ATTR_REPARSE_PT_2K	0xc0
#define ATTR_EA_INFO	0xd0
#define ATTR_EA			0xe0
#define ATTR_PROP_SET	0xf0
#define ATTR_LUS		0x100	/*Logged utility stream*/

/*File permissions*/
#define FPERM_RDONLY 0x1
#define FPERM_HIDDEN 0x2
#define FPERM_SYSTEM 0x4
#define FPERM_ARCHIVE 0x20
#define FPERM_DEVICE 0x40
#define FPERM_NORMAL 0x80
#define FPERM_TEMP 0x100
#define FPERM_SPARSE 0x200
#define FPERM_REPARSE 0x400
#define FPERM_COMPRESSED 0x800
#define FPERM_OFFLINE 0x1000
#define FPERM_NCI 0x2000	/*Not content indexed*/
#define FPERM_ENC 0x4000

#define FLAGS_DIR 0x10000000
#define FLAGS_INDX 0x20000000


/*For the attribute data there is no structure as such.*/

struct attr_std_info	{
	u64 ctime;
	u64 atime;
	u64 mtime;
	u64 rtime;
	u32 file_perms;
	u32 max_ver;
	u32 ver;
	u32 class_id;
	u32 owner_id;
	u32 sec_id;
	u64 quota;
	u64 usn;
}__attribute__((packed));

struct attr_file_name	{
	u64 ref_parent;
	u64 ctime;
	u64 atime;
	u64 mtime;
	u64 rtime;
	u64 alloc_sz;
	u64 real_sz;
	u32 flags;
	u32 ea_reparse_info;
	u8 len;
	u8 nm;
	/*Here the file name in unicode is there*/
}__attribute__((packed));

char *attribs[]={"$STANDARD_INFORMATION","$ATTRIBUTE_LIST","$FILE_NAME","$VOLUME_VERSION","$SECURITY_DESCRIPTOR","$VOLUME_NAME","$VOLUME_INFORMATION","$DATA","$INDEX_ROOT","$INDEX_ALLOCATION","$BITMAP","$SYMBOLIC_LINK","$EA_INFORMATION","$EA","$PROPERTY_SET","$LOGGED_UTILITY_STREAM"};

#define DEF_READSZ 10

struct ntfs_sys_struct	{
	kdrv *disk;
	u32 vol_lba;
	u32 mftsect;
	char *buf,*mftbuf;
	u32 read_sz;
	struct ntfs_boot *boot;
	struct mft_file_record *filerec;
	struct attr_resident *resattr;
	struct attr_nonresident *nresattr;
}ntfs_sys;


void print_memory(u8 *addr,unsigned len)
{
	while(--len)
		printk("%c",(u8)(*addr++));
}

void print_unicode(u8 *addr,int len)
{
	int i;
	while(*addr!=NULL && len-->0)	{
		printk("%c",*addr);
		addr+=2;
	}
}

void attr_read()
{
	int i=0;
	u32 *end_attr;
	while((*end_attr)!=END_ATTR_MARK && ++i<10)	{
		printk("\nAttrib:");
		if(ntfs_sys.resattr->nres_flag==0x1)	{
			printk(" Non-resident ");
			ntfs_sys.nresattr=(struct attr_nonresident *)ntfs_sys.resattr;
			if(ntfs_sys.nresattr->name_len)
				printk("%s",(char *)(ntfs_sys.nresattr+sizeof(struct attr_nonresident)));
			printk(" Type:%x (%s) Length:%x",ntfs_sys.nresattr->type,attribs[(ntfs_sys.nresattr->type-1)>>4],ntfs_sys.nresattr->len);
			ntfs_sys.resattr=(struct attr_resident *)((u32)ntfs_sys.resattr+ntfs_sys.resattr->len);
			end_attr=ntfs_sys.resattr;
			continue;
		}
		printk(" Resident ");
		printk(" Type:%x (%s) Length:%x",ntfs_sys.resattr->type,attribs[(ntfs_sys.resattr->type-1)>>4],ntfs_sys.resattr->len);
		switch(ntfs_sys.resattr->type)	{
			case ATTR_FILE_NAME:	{
				struct attr_file_name *temp;
				temp=(struct attr_file_name *)((u32)ntfs_sys.resattr+sizeof(struct attr_resident));
				printk("\nFile name:");
				print_unicode((char *)((u32)temp+sizeof(struct attr_file_name)),temp->len);
				break;
			}
		}
		ntfs_sys.resattr=(struct attr_resident *)((u32)ntfs_sys.resattr+ntfs_sys.resattr->len);
		end_attr=ntfs_sys.resattr;
	}
}

void show_frec()
{
	if(ntfs_sys.filerec->flags==FREC_DIR)
		printk("\nDirectory");
	else if(ntfs_sys.filerec->flags==FREC_IN_USE)
		printk("\nIn use");
	else
		printk("\nNot in use");
}

void ntfs_read()
{
	ntfs_sys.mftsect=(u32)(ntfs_sys.boot->mftdatalcn)*ntfs_sys.boot->sectperclust;
	printk("\nSector location of mft:%d",ntfs_sys.mftsect);
	ntfs_sys.mftbuf=(char *)get_mem(SECTOR*DEF_READSZ);
	ntfs_sys.disk->read_device(READ_DISK,(u32)ntfs_sys.mftbuf,ntfs_sys.vol_lba+ntfs_sys.mftsect,DEF_READSZ);
	ntfs_sys.filerec=(struct mft_file_record *)ntfs_sys.mftbuf;
	show_frec();
	printk("\nAttribute offset:%x",ntfs_sys.filerec->attroffset);
	ntfs_sys.resattr=(struct attr_resident *)((u32)ntfs_sys.filerec+ntfs_sys.filerec->attroffset);
	attr_read();
	free(ntfs_sys.mftbuf);
}

void ntfs_detect(u32 lba)
{
	ntfs_sys.disk=get_device("hddbios");
	ntfs_sys.buf=(char *)get_mem(SECTOR);
	ntfs_sys.disk->read_device(READ_DISK,(u32)ntfs_sys.buf,lba,DEF_READSZ);
	ntfs_sys.boot=(struct ntfs_boot *)ntfs_sys.buf;
	if(ntfs_sys.boot->sign==BOOT_SIG)	{
		if(!strncmp(ntfs_sys.boot->sysid,"NTFS",4))	{
			ntfs_sys.vol_lba=lba;
			printk("\nFilesystem NTFS detected.");
			ntfs_read();
		} else	{
			free(ntfs_sys.buf);
			return;
		}
	} else	{
		printk("\nBoot signature mismatch.");
		free(ntfs_sys.buf);
		return;
	}
	free(ntfs_sys.buf);
}














